val RCSversion = ref "";
fun RCS version = RCSversion := (!RCSversion)^version^"\n";
RCS "$Id: common.ml,v 1.17 1998/08/13 11:31:01 pxs Exp $";

(* A general purpose exception for things which I'm so sure can't    *)
(* happen that it isn't worth tracking them more precisely -- famous *)
(* last words... *)
exception Panic
exception PanicNoisily of string			(* nuff said *)
(* for when you'd call UI.error except that that doesn't type-check. *)
exception Error of string
exception Parse of string
exception QuitCWB of string

(* Let's define a few more natural pervasives *)
fun inc i = i := (!i) + 1;		(* not in 110?? *)
fun dec i = i := (!i) - 1;		(* not in 110?? *)
    
fun fst (x,_) = x

fun snd (_,x) = x

fun forall p l = let fun fall [] = true
                       | fall (h::t) = (p h) andalso (fall t)
                  in fall l
                 end

fun flatten [] = []
  | flatten (h::t) = h@(flatten t)

(* keep things if p DOES hold of them *)
fun filter p =
    let fun filt [] = []
          | filt (h::t) = let val ftail = filt t
                           in if p h then h::ftail else ftail
                          end
     in filt
    end

(* keep things if p does NOT hold of them *)
fun filterNot p =
  let fun filt [] = []
	| filt (h::t) = let val ftail = filt t
			in if p h then ftail else h::ftail
			end
  in filt
  end

fun noOp _ = ()
fun id x = x

structure Lib =
struct
   fun member eq (a,l) = List.exists (fn x => eq(x,a)) l

   fun rm eq (a,l) =
       let fun rma [] = []
             | rma (h::t) = if eq(h,a) then rma t else h::(rma t)
        in rma l
       end

   fun eq elt_eq =
       let fun equal ([],[]) = true
             | equal (a::s,b::t) = elt_eq(a,b) andalso equal(s,t)
             | equal _ = false
        in equal
       end

   fun le elt_le =
       let fun leq ([],_)        = true
             | leq (_,[])        = false
             | leq (h::t,h'::t') = elt_le(h,h') andalso
                                   (not (elt_le(h',h)) orelse leq(t,t'))
        in leq
       end

   fun del_dups eq =
       let fun dd m [] = m
             | dd m (h::t) = if member eq (h,m) then dd m t else dd (m@[h]) t
        in dd []
       end
(* Equiv to map prod on the list of all possible pairs (a1 in l1, a2 in l2)*)
(* In ptic, like a good multiplication, null iff one of its args is. *)
   fun multiply prod [] l = []
     | multiply prod l [] = [] (* unnecessary, but avoids walking down l *)
     | multiply prod (h::t) l =
       let (* m l equiv (map prod) on list of all pairs (h,h' in l)  *)
	 fun m [] = []
	   | m (h'::t') = prod(h,h')::(m t')
       in (m l)@(multiply prod t l)
       end

(* Given a predicate and a list, return first elt on lists satisfying pred *)
   exception First
   fun first p l = let fun f [] = raise First
			 | f (h::t) = if p h then h else f t
		   in f l
		   end

   fun mkstr mkstrelt sep []     = ""

     | mkstr mkstrelt sep [a]    = mkstrelt a
     | mkstr mkstrelt sep (h::t) = (mkstrelt h)^sep^(mkstr mkstrelt sep t)

   val ran = ref 123
   fun random ub = (ran := (1005 * !ran + 7473) mod 8192;
                    (!ran) div (8192 div ub + 1))

(* return a line minus any leading or trailing whitespace  *)
   fun get_line infile =
       let fun strip (#" "::t) = strip t
             | strip (#"\t"::t) = strip t
             | strip (#"\n"::t) = strip t
             | strip l = l
           val revline = strip(rev(strip(explode(TextIO.inputLine infile))))
        in implode(rev revline)
       end

   fun startsWithCapital string = 
     (if (ord string) >= (ord #"A") andalso
       (ord string) <= (ord #"Z") then true
     else false) handle Ord => false

   fun lexicographicLe (le1, le2) ((a1,a2),(b1,b2)) =
     if le1 (a1, b1) then
       if le1 (b1, a1) then le2 (a2, b2) else true
     else false

(* is_term_in, is_term_out copied from SML Top-level Comparison, bell labs. *)
   fun is_term_in (instream : TextIO.instream) =
     let val (rd as TextPrimIO.RD{ioDesc,...}, buf) =
       TextIO.StreamIO.getReader(TextIO.getInstream instream)
     in TextIO.setInstream
       (instream, TextIO.StreamIO.mkInstream(rd, SOME buf));
       case ioDesc of
	 NONE => false
       | SOME desc => (OS.IO.kind desc = OS.IO.Kind.tty)
     end

   fun is_term_out (outstream: TextIO.outstream) =
     let val (wr as TextPrimIO.WR{ioDesc,...},buf) =
       TextIO.StreamIO.getWriter(TextIO.getOutstream outstream)
     in TextIO.setOutstream (outstream, TextIO.StreamIO.mkOutstream(wr,buf));
       case ioDesc
	 of NONE => false
       | SOME desc => (OS.IO.kind desc = OS.IO.Kind.tty)
     end
end

